package com.mysher.devlib.uvc.renderer;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;

import java.nio.ByteBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class YuvGLRenderer implements GLSurfaceView.Renderer {


    private GLProgram mProgram;

    // GLSurfaceView宽度
    private int mScreenWidth;

    // GLSurfaceView高度
    private int mScreenHeight;

    // 预览YUV数据宽度
    private int mVideoWidth;

    // 预览YUV数据高度
    private int mVideoHeight;

    // vPMatrix is an abbreviation for "Model View Projection Matrix"
    private float[] vPMatrix = new float[16];
    private float[] projectionMatrix = new float[16];
    private float[] viewMatrix = new float[16];

    private float[] mMatrixCurrent = new float[]{
            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 0, 0, 1
    };

    // y分量数据
    private ByteBuffer y = ByteBuffer.allocate(0);

    // u分量数据
    private ByteBuffer u = ByteBuffer.allocate(0);

    // v分量数据
    private ByteBuffer v = ByteBuffer.allocate(0);

    // uv分量数据
    private ByteBuffer uv = ByteBuffer.allocate(0);

    // YUV数据格式 0 -> I420  1 -> NV12  2 -> NV21
    private int type = 0;

    // 标识GLSurfaceView是否准备好
    private boolean hasVisibility = false;


    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        // 配置OpenGL ES 环境
        mProgram = new GLProgram();
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        //Log.e("TAG", "onSurfaceChanged width :" +width+"height"+height);
        if (y.capacity() > 0) {
            y = ByteBuffer.allocate(0);
        }
        if (u.capacity() > 0) {
            u = ByteBuffer.allocate(0);
        }
        if (v.capacity() > 0) {
            v = ByteBuffer.allocate(0);
        }
        this.mScreenWidth = width;
        this.mScreenHeight = height;
        this.mVideoWidth = 0;
        this.mVideoHeight = 0;
        GLES20.glViewport(0, 0, mScreenWidth, mScreenHeight);
        //float ratio = mScreenWidth / (float) mScreenHeight;


        // this projection matrix is applied to object coordinates
        // in the onDrawFrame() method
        Matrix.frustumM(projectionMatrix, 0, -1, 1, -1f, 1f, 3f, 7f);

        // Set the camera position (View matrix)
//        Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, -3f, 0f, 0f, 0f, 1.0f, 0.0f, 0.0f)

        Matrix.setLookAtM(viewMatrix, 0, 0F, 0F, 3.0f, 0f, 0f, 0f, 0f, 1.0f, 0f);
        //Matrix.rotateM(mMatrixCurrent,0,90,1,1,1);

        if (mVideoWidth > 0 && mVideoHeight > 0) {
            createBuffers(mVideoWidth, mVideoHeight);
        }
        hasVisibility = true;

    }

    @Override
    public void onDrawFrame(GL10 gl) {
        synchronized (this) {
            if (y.capacity() > 0) {
                y.position(0);
                if (type == 0) {
                    u.position(0);
                    v.position(0);
                    mProgram.feedTextureWithImageData(y, u, v, mVideoWidth, mVideoHeight);
                } else {
                    uv.position(0);
                    mProgram.feedTextureWithImageData(y, uv, mVideoWidth, mVideoHeight);
                }
                // Redraw background color
                GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

                // Calculate the projection and view transformation
                Matrix.multiplyMM(vPMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
                try {
                    mProgram.drawTexture(vPMatrix, type);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void setYuvDataSize(int width, int height) {
        if (y != null) {
            y.clear();
        }
        if (u != null) {
            u.clear();
        }
        if (v != null) {
            v.clear();
        }
        if (uv != null) {
            uv.clear();
        }
        if (width > 0 && height > 0) {
            // 调整比例
            //createBuffers(width, height);
            // 初始化容器
            if (width != mVideoWidth || height != mVideoHeight) {
                createBuffers(width, height);
                this.mVideoWidth = width;
                this.mVideoHeight = height;
                int yarraySize = width * height;
                int uvarraySize = yarraySize / 4;
                synchronized (this) {
                    y = ByteBuffer.allocate(yarraySize);
                    u = ByteBuffer.allocate(uvarraySize);
                    v = ByteBuffer.allocate(uvarraySize);
                    uv = ByteBuffer.allocate(uvarraySize * 2);
                }
            }
        }
    }

    private void createBuffers(int width, int height) {
        if (mScreenWidth > 0 && mScreenHeight > 0) {
            float f1 = mScreenHeight / (float) mScreenWidth;
            float f2 = height / (float) width;
            if (f1 == f2) {
                mProgram.createBuffers(GLProgram.squareVertices);
            } else if (f1 < f2) {
                float widthScale = f1 / f2;
                mProgram.createBuffers(
                        new float[]{-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f});
            } else {
                float heightScale = f2 / f1;
                mProgram.createBuffers(
                        new float[]{-1.0f, -heightScale, 1.0f, -heightScale,
                                -1.0f, heightScale, 1.0f, heightScale});
            }
        }
    }

    /**
     * 预览YUV格式数据
     *
     * @param yuvdata yuv格式的数据
     * @param type    YUV数据的格式 0 -> I420  1 -> NV12  2 -> NV21
     */
    public void feedData(byte[] yuvdata, int type) {
        synchronized (this) {
            if (hasVisibility) {
                this.type = type;
                if (type == 0) {
                    y.clear();
                    u.clear();
                    v.clear();
                    y.put(yuvdata, 0, mVideoWidth * mVideoHeight);
                    u.put(yuvdata, mVideoWidth * mVideoHeight, mVideoWidth * mVideoHeight / 4);
                    v.put(yuvdata, mVideoWidth * mVideoHeight * 5 / 4, mVideoWidth * mVideoHeight / 4);
                } else {
                    y.clear();
                    uv.clear();
                    y.put(yuvdata, 0, mVideoWidth * mVideoHeight);
                    uv.put(yuvdata, mVideoWidth * mVideoHeight, mVideoWidth * mVideoHeight / 2);
                }
            }
        }
    }

    public void destroyGL() {
        // 清楚掉黑色框框
        // 清楚掉黑色框框
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        // 渲染
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    }
}
